package com.itjeffrey.autocode.controller;

import com.itjeffrey.autocode.bo.ProcessBO;
import com.itjeffrey.autocode.bo.ProcessDefied;
import com.itjeffrey.autocode.bo.ProcessTaskBO;
import com.itjeffrey.autocode.bo.UserInfoBO;
import com.itjeffrey.autocode.common.PageDomain;
import com.itjeffrey.autocode.common.PageResult;
import com.itjeffrey.autocode.common.Result;
import com.itjeffrey.autocode.service.UserService;
import com.itjeffrey.autocode.util.BeanOprUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 流程控制器
 * @From: Jeffrey
 * @Date: 2021/5/25
 */
@RestController
@RequestMapping(ControllerConstants.PROCESS_URL_PREFIX)
public class ProcessController extends ControllerConstants {

    @Resource
    private UserService userService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ProcessEngineConfigurationImpl processEngineConfiguration;

    /**
     * 获取登录用户待处理任务
     * @param processTaskBO (loginName与processInsId必须)
     * @return
     */
    @PostMapping("queryTasks")
    public ResponseEntity<Result> queryTasks(@RequestBody ProcessTaskBO processTaskBO){
        List<TaskEntityImpl> tasks = new ArrayList<>();
        TaskQuery taskQuery = taskService.createTaskQuery();
        Result user = userService.queryOne(processTaskBO.getLoginName());
        if(Objects.nonNull(user.getData())){
            UserInfoBO userInfoBO = (UserInfoBO) user.getData();
            List<Task> tasks1 =
                    taskQuery.taskCandidateOrAssigned(userInfoBO.getUsername()).processInstanceId(processTaskBO.getProcessInsId()).list();
            tasks1.forEach(task -> {
                TaskEntityImpl taskEntity = new TaskEntityImpl();
                taskEntity.setId(task.getId());
                taskEntity.setAssignee(task.getAssignee());
                taskEntity.setCategory(task.getCategory());
                taskEntity.setName(task.getName());
                taskEntity.setProcessDefinitionId(task.getProcessDefinitionId());
                taskEntity.setProcessInstanceId(task.getProcessInstanceId());
                taskEntity.setExecutionId(task.getExecutionId());
                taskEntity.setOwner(task.getOwner());
                taskEntity.setDueDate(task.getDueDate());
                taskEntity.setDescription(task.getDescription());
                taskEntity.setCreateTime(task.getCreateTime());
                tasks.add(taskEntity);
            });
        }
        return ResponseEntity.ok(Result.ok(tasks.iterator().next()));
    }

    /**
     * 启动流程实例，返回工作流编号
     * @param processBO 流程定义Id
     * @return 流程实例ID（工作流编号）
     */
    @PostMapping("/startInstance")
    public ResponseEntity<Result> startInstance(@RequestBody ProcessBO processBO){
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processBO.getId());
        return ResponseEntity.ok(Result.ok(processInstance.getId()));
    }

    /**
     * 执行任务
     * @param processTaskBO （loginName与taskId必须）
     * @return
     */
    @PostMapping("complete")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Result> completeTask(@RequestBody ProcessTaskBO processTaskBO){
        Result user = userService.queryOne(processTaskBO.getLoginName());
        if(Objects.nonNull(user.getData())) {
            UserInfoBO userInfoBO = (UserInfoBO) user.getData();
            //获取流程实例
            taskService.claim(processTaskBO.getTaskId(), userInfoBO.getUsername());
        }
        taskService.complete(processTaskBO.getTaskId());
        return ResponseEntity.ok(Result.ok());
    }

    /**
     * 流程申请信息查询
     */
    @PostMapping("/applyInfo/query")
    public ResponseEntity<Result> query(@RequestBody PageDomain pageDomain) {
        PageResult<ProcessDefied> pageResult = new PageResult<>();
        BeanOprUtils.copyProperties(pageDomain, pageResult);
        ProcessDefinitionQuery processDefinitionQuery = repositoryService
                .createProcessDefinitionQuery();
        if (StringUtils.hasText(pageDomain.getDefinitionName())) {
            processDefinitionQuery.processDefinitionNameLike(pageDomain.getDefinitionName());
        }
        List<ProcessDefinition> processDefinitions = processDefinitionQuery
                .orderByDeploymentId()
                .desc()
                .orderByProcessDefinitionVersion()
                .desc()
                .listPage(pageDomain.start(), pageDomain.end());

        List<ProcessDefied> data = new ArrayList<>();

        processDefinitions.forEach(processDefinition -> {
            ProcessDefied defined = new ProcessDefied();
            defined.setId(processDefinition.getId());
            defined.setName(processDefinition.getName());
            defined.setVersion(processDefinition.getVersion());
            defined.setKey(processDefinition.getKey());
            defined.setBpmn(processDefinition.getResourceName());
            defined.setPng(processDefinition.getDiagramResourceName());
            defined.setDeploymentId(processDefinition.getDeploymentId());
            long instanceCount =
                    historyService.createHistoricActivityInstanceQuery().processDefinitionId(processDefinition.getId()).count();
            if(instanceCount > 0){
                //若此流程定义ID下没有流程实例则流程实例未启动(流程定义未发布)
                defined.setStatus(1);
            }else {
                defined.setStatus(0);
            }
            data.add(defined);
        });

        long count = processDefinitionQuery.orderByProcessDefinitionVersion().asc().count();
        pageResult.setTotals((int) count);
        pageResult.setData(data);
        return ResponseEntity.ok(Result.ok(pageResult));
    }

    /**
     * 流程图高亮显示
     * @throws Exception
     */
//    public void queryProHighLighted(String processInstanceId) throws Exception {
//        //获取历史流程实例
//        HistoricProcessInstance processInstance =  historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//        //获取流程图
//        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
//
//        ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
//        ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());
//
//        List<HistoricActivityInstance> highLightedActivitList =  historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
//        //高亮环节id集合
//        List<String> highLightedActivitis = new ArrayList<String>();
//
//        //高亮线路id集合
//        List<String> highLightedFlows = getHighLightedFlows(definitionEntity,highLightedActivitList);
//
//        for(HistoricActivityInstance tempActivity : highLightedActivitList){
//            String activityId = tempActivity.getActivityId();
//            highLightedActivitis.add(activityId);
//        }
//        //配置字体
//        InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitis, highLightedFlows,"宋体","微软雅黑","黑体",null,2.0);
//        BufferedImage bi = ImageIO.read(imageStream);
//        File file = new File("demo2.png");
//        if(!file.exists()) file.createNewFile();
//        FileOutputStream fos = new FileOutputStream(file);
//        ImageIO.write(bi, "png", fos);
//        fos.close();
//        imageStream.close();
//        System.out.println("图片生成成功");
//    }
    /**
     * 获取需要高亮的线
     * @param processDefinitionEntity
     * @param historicActivityInstances
     * @return
     */
//    private List<String> getHighLightedFlows(
//            ProcessDefinitionEntity processDefinitionEntity,
//            List<HistoricActivityInstance> historicActivityInstances) {
//
//        List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
//        for (int i = 0; i < historicActivityInstances.size() - 1; i++) {// 对历史流程节点进行遍历
//            ActivityImpl activityImpl = processDefinitionEntity
//                    .findActivity(historicActivityInstances.get(i)
//                            .getActivityId());// 得到节点定义的详细信息
//            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();// 用以保存后需开始时间相同的节点
//            ActivityImpl sameActivityImpl1 = processDefinitionEntity
//                    .findActivity(historicActivityInstances.get(i + 1)
//                            .getActivityId());
//            // 将后面第一个节点放在时间相同节点的集合里
//            sameStartTimeNodes.add(sameActivityImpl1);
//            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
//                HistoricActivityInstance activityImpl1 = historicActivityInstances
//                        .get(j);// 后续第一个节点
//                HistoricActivityInstance activityImpl2 = historicActivityInstances
//                        .get(j + 1);// 后续第二个节点
//                if (activityImpl1.getStartTime().equals(
//                        activityImpl2.getStartTime())) {
//                    // 如果第一个节点和第二个节点开始时间相同保存
//                    ActivityImpl sameActivityImpl2 = processDefinitionEntity
//                            .findActivity(activityImpl2.getActivityId());
//                    sameStartTimeNodes.add(sameActivityImpl2);
//                } else {
//                    // 有不相同跳出循环
//                    break;
//                }
//            }
//            List<PvmTransition> pvmTransitions = activityImpl
//                    .getOutgoingTransitions();// 取出节点的所有出去的线
//            for (PvmTransition pvmTransition : pvmTransitions) {
//                // 对所有的线进行遍历
//                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition
//                        .getDestination();
//                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
//                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
//                    highFlows.add(pvmTransition.getId());
//                }
//            }
//        }
//        return highFlows;
//    }

}
